let drawParams: any;
let drawCanvas: any;
let drawContext: any;
let drawScale = 1;

let points: any;
let lastTime = 0;

export function startWriting(canvas: any, canvasContext: any, params: any, e: any) {
  drawParams = params;
  if (drawParams.scale) drawScale = drawParams.scale;
  drawCanvas = canvas;
  drawContext = canvasContext;

  if (drawParams.mode === 'flupen') {
    drawContext.globalCompositeOperation = 'xor';
    drawContext.globalAlpha = 0.5;
  } else {
    drawContext.globalCompositeOperation = 'source-over';
    drawContext.globalAlpha = 1;
  }

  const pos = getOffsetPosition(canvas, e, drawScale);
  points = [pos];
  if (drawParams.mode === 'pen' || drawParams.mode === 'flupen') {
    drawContext.beginPath();
    drawContext.moveTo(pos.x, pos.y);
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
  }
}

export function writingCurve(e: any) {
  if (!drawCanvas) return;
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const len = points.length;
  const time = new Date().getTime();
  if (time - lastTime >= 50) {
    if (len >= 2) {
      const controlP = points[len - 1];
      if (len > 2) {
        points = points.splice(len - 2, 2);
      }
      points.push(endP);
      const midP = getCurveMidPoint(controlP.x, controlP.y, endP.x, endP.y);
      drawContext.quadraticCurveTo(controlP.x, controlP.y, midP.x, midP.y);
      drawContext.stroke();
    } else {
      points.push(endP);
    }
    lastTime = time;
  }
}
export function writingRoundRect(e: any) {
  if (!drawCanvas) return;
  const radius = 20 * drawScale; //圆角
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;

  const time = new Date().getTime();
  if (time - lastTime >= 100) {
    if (len >= 2) {
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    if (width < radius * 2 || height < radius * 2) return;
    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.arc(startP.x + radius, startP.y + radius, radius, Math.PI, 1.5 * Math.PI);
    drawContext.lineTo(startP.x + width - radius, startP.y);
    drawContext.arc(startP.x + width - radius, startP.y + radius, radius, 1.5 * Math.PI, 2 * Math.PI);
    drawContext.lineTo(startP.x + width, startP.y + height - radius);
    drawContext.arc(startP.x + width - radius, startP.y + height - radius, radius, 0, 0.5 * Math.PI);
    drawContext.lineTo(startP.x + radius, startP.y + height);
    drawContext.arc(startP.x + radius, startP.y + height - radius, radius, 0.5 * Math.PI, Math.PI);
    drawContext.closePath();
    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if (len < 2) points.push(endP);
    else points[1] = endP;
  }
}
export function writingEllipse(e: any) {
  if (!drawCanvas) return;
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;

  const time = new Date().getTime();
  if (time - lastTime >= 100) {
    if (len >= 2) {
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    if (width > 10 * drawScale && height > 10 * drawScale) {
      drawContext.beginPath();
      drawContext.strokeStyle = drawParams.color;
      drawContext.lineWidth = drawParams.size;
      drawContext.ellipse(startP.x + width / 2, startP.y + height / 2, width / 2, height / 2, 0, 0, Math.PI * 2)
      drawContext.stroke();
      drawContext.restore();
    }
    lastTime = time;
    if (len < 2) points.push(endP);
    else points[1] = endP;
  }
}
export function writingRegtri(e: any) {
  if (!drawCanvas) return;
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;

  const time = new Date().getTime();
  if (time - lastTime >= 100) {
    if (len >= 2) {
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.moveTo(startP.x + width / 2, startP.y);
    drawContext.lineTo(startP.x, startP.y + height);
    drawContext.lineTo(startP.x + width, startP.y + height);
    drawContext.closePath();
    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if (len < 2) points.push(endP);
    else points[1] = endP;
  }
}
export function writingRighttri(e: any) {
  if (!drawCanvas) return;
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;

  const time = new Date().getTime();
  if (time - lastTime >= 100) {
    if (len >= 2) {
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.moveTo(startP.x, startP.y);
    drawContext.lineTo(startP.x, startP.y + height);
    drawContext.lineTo(startP.x + width, startP.y + height);
    drawContext.closePath();
    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if (len < 2) points.push(endP);
    else points[1] = endP;
  }
}
export function writingArrowRight(e: any) {
  if (!drawCanvas) return;
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;

  const time = new Date().getTime();
  if (time - lastTime >= 100) {
    if (len >= 2) {
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }
    const arrowLen = 20 * drawScale;
    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    if (Math.abs(width) < arrowLen && Math.abs(height) < arrowLen) return;
    let angleA = Math.round(Math.atan2(height, width) * 180 / Math.PI);

    const angle = 30;
    const hu1 = (angle + angleA) * Math.PI / 180
    const ah1 = Math.sin(hu1) * arrowLen;
    const aw1 = Math.cos(hu1) * arrowLen;

    const hu2 = (angle - angleA) * Math.PI / 180
    const ah2 = Math.sin(hu2) * arrowLen;
    const aw2 = Math.cos(hu2) * arrowLen;

    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.moveTo(startP.x, startP.y);
    drawContext.lineTo(endP.x, endP.y);
    drawContext.lineTo(endP.x - aw1, endP.y - ah1);
    drawContext.moveTo(endP.x, endP.y);
    drawContext.lineTo(endP.x - aw2, endP.y + ah2);

    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if (len < 2) points.push(endP);
    else points[1] = endP;
  }
}

export function stopWriting(e: any) {
  if (!e) {
    return getWritingRecord();
  }
  if (drawContext) drawContext.restore();
  const record = getWritingRecord();

  drawCanvas = null;
  drawContext = null;
  drawParams = null;

  points = [];
  lastTime = 0;

  return record;
}

export function erase(canvas: any, context: { save: () => void; beginPath: () => void; arc: (arg0: number, arg1: number, arg2: number, arg3: number, arg4: number) => void; clip: () => void; clearRect: (arg0: number, arg1: number, arg2: any, arg3: any) => void; restore: () => void; }, params: { scale: number; size: number; width: any; height: any; }, e: any) {
  const point = getOffsetPosition(canvas, e, params.scale);
  context.save();
  context.beginPath();
  context.arc(point.x, point.y, params.size * params.scale / 2, 0, 2 * Math.PI);
  context.clip();
  context.clearRect(0, 0, params.width, params.height);
  context.restore();
  points.push({ x: point.x, y: point.y });
}

export function clear(context: { clearRect: (arg0: number, arg1: number, arg2: any, arg3: any) => void; }, params: { width: any; height: any; }) {
  context.clearRect(0, 0, params.width, params.height);
}

function getWritingRecord() {
  if (!drawParams) return null;
  const record = drawParams;
  record.points = points;
  return record;
}

export function getOffsetPosition(canvas: { getBoundingClientRect: () => any; }, e: { changedTouches: any[]; }, scale: number) {
  const event = e instanceof MouseEvent ? e : e.changedTouches[0];
  // console.log('e', event.pageX, event.pageY)
  const canvasRect = canvas.getBoundingClientRect();
  const x = event.pageX - canvasRect.x;
  const y = event.pageY - canvasRect.y;
  return { x: Math.round(x * scale), y: Math.round(y * scale) }
}
function getCurveMidPoint(x1: any, y1: any, x2: number, y2: number) {
  const x = (x1 + x2) / 2;
  const y = (y1 + y2) / 2;
  return { x, y };
}

export function drawShape(context: any, ele: any) {
  context.globalCompositeOperation = 'source-over';
  context.globalAlpha = 1;
  switch (ele.mode) {
    case 'arrowright':
      drawArrowRight(context, ele);
      break;
    case 'roundrect':
      drawRoundRect(context, ele);
      break;
    case 'ellipse':
      drawEllipse(context, ele);
      break;
    case 'regtri':
      drawRegtri(context, ele);
      break;
    case 'righttri':
      drawRighttri(context, ele);
      break;
  }
}

function drawRighttri(context: { beginPath: () => void; strokeStyle: any; lineWidth: any; moveTo: (arg0: any, arg1: any) => void; lineTo: (arg0: any, arg1: any) => void; closePath: () => void; stroke: () => void; restore: () => void; }, ele: { points: string | any[]; color: any; size: any; }) {
  if (ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.moveTo(startP.x, startP.y);
  context.lineTo(startP.x, startP.y + height);
  context.lineTo(startP.x + width, startP.y + height);
  context.closePath();
  context.stroke();
  context.restore();
}
function drawRoundRect(context: { beginPath: () => void; strokeStyle: any; lineWidth: any; arc: (arg0: number, arg1: number, arg2: number, arg3: number, arg4: number) => void; lineTo: (arg0: number, arg1: number) => void; closePath: () => void; stroke: () => void; restore: () => void; }, ele: { scale: number; points: string | any[]; color: any; size: any; }) {
  const radius = 20 * ele.scale; //圆角
  if (ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.arc(startP.x + radius, startP.y + radius, radius, Math.PI, 1.5 * Math.PI);
  context.lineTo(startP.x + width - radius, startP.y);
  context.arc(startP.x + width - radius, startP.y + radius, radius, 1.5 * Math.PI, 2 * Math.PI);
  context.lineTo(startP.x + width, startP.y + height - radius);
  context.arc(startP.x + width - radius, startP.y + height - radius, radius, 0, 0.5 * Math.PI);
  context.lineTo(startP.x + radius, startP.y + height);
  context.arc(startP.x + radius, startP.y + height - radius, radius, 0.5 * Math.PI, Math.PI);
  context.closePath();
  context.stroke();
  context.restore();
}
function drawRegtri(context: { beginPath: () => void; strokeStyle: any; lineWidth: any; moveTo: (arg0: any, arg1: any) => void; lineTo: (arg0: any, arg1: any) => void; closePath: () => void; stroke: () => void; restore: () => void; }, ele: { points: string | any[]; color: any; size: any; }) {
  if (ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.moveTo(startP.x + width / 2, startP.y);
  context.lineTo(startP.x, startP.y + height);
  context.lineTo(startP.x + width, startP.y + height);
  context.closePath();
  context.stroke();
  context.restore();
}
function drawEllipse(context: { beginPath: () => void; strokeStyle: any; lineWidth: any; ellipse: (arg0: any, arg1: any, arg2: number, arg3: number, arg4: number, arg5: number, arg6: number) => void; stroke: () => void; restore: () => void; }, ele: { points: string | any[]; color: any; size: any; }) {
  if (ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.ellipse(startP.x + width / 2, startP.y + height / 2, width / 2, height / 2, 0, 0, Math.PI * 2)
  context.stroke();
  context.restore();
}
function drawArrowRight(context: { beginPath: () => void; strokeStyle: any; lineWidth: any; moveTo: (arg0: any, arg1: any) => void; lineTo: (arg0: number, arg1: number) => void; stroke: () => void; restore: () => void; }, ele: { points: string | any[]; scale: number; color: any; size: any; }) {
  if (ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;

  const arrowLen = 20 * ele.scale; //箭头长度
  const angle = 30; // 箭头夹角
  //线在屏幕中的坐标夹角
  let angleA = Math.round(Math.atan2(height, width) * 180 / Math.PI);
  // 上半箭头的坐标
  const hu1 = (angle + angleA) * Math.PI / 180
  const ah1 = Math.sin(hu1) * arrowLen;
  const aw1 = Math.cos(hu1) * arrowLen;
  // 下半箭头的坐标
  const hu2 = (angle - angleA) * Math.PI / 180
  const ah2 = Math.sin(hu2) * arrowLen;
  const aw2 = Math.cos(hu2) * arrowLen;

  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.moveTo(startP.x, startP.y);
  context.lineTo(endP.x, endP.y);
  context.lineTo(endP.x - aw1, endP.y - ah1);
  context.moveTo(endP.x, endP.y);
  context.lineTo(endP.x - aw2, endP.y + ah2);

  context.stroke();
  context.restore();
}
